#include "DGL3ProgramEnums.inc"
#include "DGL3Common.glsl"
#include "DGL3LightsUniform.glsl"

layout(std140) 
uniform BBoxData
{
	mat4 uBboxData[1024];
};

// #ifdef VERTEX_SHADER

	// layout(location = GE_VA_Position) in vec3 aPosition;
	// layout(location = GE_VA_Normal) in vec3 aNormal;
	
	// out vec3 normal;
	// flat out int num;

	// void main(void)
	// {
		// num = gl_InstanceID;
		// mat4 transform = uBboxData[2*num];
		// mat4 pvm = uProjectionMatrix * uViewMatrix * transform;
		
		// gl_Position = pvm * vec4(aPosition, 1.0);
		// normal = normalize( FormNormalMatrix(transform, false) * aNormal );		
	// }

// #endif

#ifdef VERTEX_SHADER

	// layout(location = GE_VA_Position) in vec3 aPosition;
	
	flat out int number;
	
	void main(void)
	{
		number = gl_InstanceID;
		// gl_Position = vec4(aPosition, 1.0);
	}

#endif

//-----------------------------------------

#ifdef GEOMETRY_SHADER

	layout(points) in;
	layout(triangle_strip, max_vertices = 36) out;
	
	out vec3 normal;
	flat out int num;
	flat in int number[];
		
	void main(void)
	{
		// num = gl_PrimitiveIDIn;
		num = number[0];
		// mat4 transform = uBboxData[2*num];
		mat4 transform = uBboxData[num];
		transform[0][3] = 0;
		transform[1][3] = 0;
		transform[2][3] = 0;
		transform[3][3] = 1;
		mat4 pvm = uProjectionMatrix * uViewMatrix * transform;
		// ff - front face: !0 in case of symmetry
		// float ff = uBboxData[2*num+1][3][1];
		//float ff = uBboxData[num][3][3];
		// // // float ff = 0;
				
		vec4 pnt[8];
		pnt[0] = pvm * vec4( 0, 0, 0, 1 );
		pnt[1] = pvm * vec4( 1, 0, 0, 1 );
		pnt[2] = pvm * vec4( 1, 1, 0, 1 );
		pnt[3] = pvm * vec4( 0, 1, 0, 1 );		
		pnt[4] = pvm * vec4( 0, 0, 1, 1 );
		pnt[5] = pvm * vec4( 1, 0, 1, 1 );
		pnt[6] = pvm * vec4( 1, 1, 1, 1 );
		pnt[7] = pvm * vec4( 0, 1, 1, 1 );
		
		vec3 n[6];
		// // // if ( ff != 0 )
		// // // {
			// // // n[0] = -normalize( ( transform * vec4( 0, -1,  0, 0 ) ).xyz );
			// // // n[1] = -normalize( ( transform * vec4( 1,  0,  0, 0 ) ).xyz );
			// // // n[2] = -normalize( ( transform * vec4( 0,  1,  0, 0 ) ).xyz );
			// // // n[3] = -normalize( ( transform * vec4( -1, 0,  0, 0 ) ).xyz );
			// // // n[4] = -normalize( ( transform * vec4( 0,  0,  1, 0 ) ).xyz );
			// // // n[5] = -normalize( ( transform * vec4( 0,  0, -1, 0 ) ).xyz );
		// // // }
		// // // else
		// // // {
			n[0] = normalize( ( transform * vec4( 0, -1,  0, 0 ) ).xyz );
			n[1] = normalize( ( transform * vec4( 1,  0,  0, 0 ) ).xyz );
			n[2] = normalize( ( transform * vec4( 0,  1,  0, 0 ) ).xyz );
			n[3] = normalize( ( transform * vec4( -1, 0,  0, 0 ) ).xyz );
			n[4] = normalize( ( transform * vec4( 0,  0,  1, 0 ) ).xyz );
			n[5] = normalize( ( transform * vec4( 0,  0, -1, 0 ) ).xyz );
		// // // }
		
		// if ( ff != 0 )
			// for ( int i = 0 ; i < 6 ; i++ )
				// n[i] = -n[i];
				
		////////////////////////////////////////////////////////////////////////		

		normal = n[0];
		if ( dot( uViewDirection, normal ) <= 0 )
		{		
			gl_Position = pnt[0]; EmitVertex();
			gl_Position = pnt[1]; EmitVertex();
			gl_Position = pnt[5]; EmitVertex();
			EndPrimitive();
			gl_Position = pnt[0]; EmitVertex();
			gl_Position = pnt[5]; EmitVertex();
			gl_Position = pnt[4]; EmitVertex();
			EndPrimitive();
		}
		
		normal = n[1];
		if ( dot( uViewDirection, normal ) <= 0 )
		{
			gl_Position = pnt[1]; EmitVertex();
			gl_Position = pnt[2]; EmitVertex();
			gl_Position = pnt[6]; EmitVertex();
			EndPrimitive();
			gl_Position = pnt[1]; EmitVertex();
			gl_Position = pnt[6]; EmitVertex();
			gl_Position = pnt[5]; EmitVertex();
			EndPrimitive();
		}
		
		normal = n[2];	
		if ( dot( uViewDirection, normal ) <= 0 )
		{
			gl_Position = pnt[2]; EmitVertex();
			gl_Position = pnt[3]; EmitVertex();
			gl_Position = pnt[7]; EmitVertex();
			EndPrimitive();
			gl_Position = pnt[2]; EmitVertex();
			gl_Position = pnt[7]; EmitVertex();
			gl_Position = pnt[6]; EmitVertex();
			EndPrimitive();		
		}
		
		normal = n[3];	
		if ( dot( uViewDirection, normal ) <= 0 )
		{
			gl_Position = pnt[3]; EmitVertex();
			gl_Position = pnt[0]; EmitVertex();
			gl_Position = pnt[4]; EmitVertex();
			EndPrimitive();
			gl_Position = pnt[3]; EmitVertex();
			gl_Position = pnt[4]; EmitVertex();
			gl_Position = pnt[7]; EmitVertex();
			EndPrimitive();
		}
		
		normal = n[4];	
		if ( dot( uViewDirection, normal ) <= 0 )
		{
			gl_Position = pnt[4]; EmitVertex();
			gl_Position = pnt[6]; EmitVertex();
			gl_Position = pnt[7]; EmitVertex();
			EndPrimitive();
			gl_Position = pnt[4]; EmitVertex();
			gl_Position = pnt[5]; EmitVertex();
			gl_Position = pnt[6]; EmitVertex();
			EndPrimitive();
		}
		
		normal = n[5];	
		if ( dot( uViewDirection, normal ) <= 0 )
		{
			gl_Position = pnt[0]; EmitVertex();
			gl_Position = pnt[3]; EmitVertex();
			gl_Position = pnt[2]; EmitVertex();
			EndPrimitive();
			gl_Position = pnt[0]; EmitVertex();
			gl_Position = pnt[2]; EmitVertex();
			gl_Position = pnt[1]; EmitVertex();
			EndPrimitive();		
		}
	}

#endif

#ifdef FRAGMENT_SHADER
	
	flat in int num;
	in vec3 normal;
	
	out vec4 FragColor;
	
	void main(void)
	{		
		vec4 diffClr = vec4( uBboxData[num][0][3], uBboxData[num][1][3], uBboxData[num][2][3], uBboxData[num][3][3] );

		// // // mat4 colors = uBboxData[2*num+1];
		// // // // vec4 diffClr = vec4( colors[0][0], colors[1][0], colors[2][0], colors[3][0] );
		// // // vec4 diffClr = colors[0];
		// // // // vec3 ambClr  = vec3( colors[0][1], colors[1][1], colors[2][1] );
		// // // vec3 ambClr  = colors[1].xyz;
		// // // // vec3 specClr = vec3( colors[0][2], colors[1][2], colors[2][2] );
		// // // vec3 specClr = colors[2].xyz;
		// // // float shininess = colors[2][3];
		// // // vec4 markClr = colors[3];
		
		vec4 diffuseLight = vec4(0.0, 0.0, 0.0, diffClr.a);
		// // // vec3 specularLight = vec3(0.0);
	
		for (int i = 0; i < uNumLight; ++i)
		{
			Light _li;
			if (i == 0)
				_li = uLight_1;
			else if (i == 1)
				_li = uLight_2;
			else if (i == 2)
				_li = uLight_3;
			else if (i == 3)
				_li = uLight_4;
			else if (i == 4)
				_li = uLight_5;
			else if (i == 5)
				_li = uLight_6;
			else if (i == 6)
				_li = uLight_7;
			else if (i == 7)
				_li = uLight_8;

			vec3 lightDir = _li.Direction;

			float NDotL = max(dot(normal, -lightDir), 0.0);
			
			vec3 diff = diffClr.rgb;
			diff = NDotL * diff * _li.Diffuse.rgb;

			// // // vec3 lightReflect = reflect(lightDir, normal);
			// // // float RDotV = max(dot(lightReflect, -uViewDirection), 0.01);
			// // // vec3 spec = vec3(0.0f);
			// // // if (shininess != 0.0f)
				// // // spec = specClr * uLight[i].Specular.rgb * (pow(RDotV, shininess));
				
			// // // // normilize specular
			// // // //spec *= (uMaterial.Shininess + 1.0f)/(2.0f * 3.1415926f);
			
			diffuseLight.rgb += diff;
			// // // specularLight += spec;
		}
		
		// // // vec4 diffuse = vec4(ambClr * 0.2f, 0.0f) + diffuseLight + vec4(specularLight, 0.0f);
		
		// // // if (markClr.w != 0.0f)
		// // // {
			// // // float a = markClr.a;
			// // // diffuse = vec4(markClr.rgb * a + diffuse.rgb * (1.0f - a), diffuse.a);
		// // // }
		
		// // // FragColor = diffuse;
		FragColor = diffuseLight;
	}

#endif

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

#ifdef GEOMETRY_SHADER_WIRED

	layout(points) in;
	layout(line_strip, max_vertices = 24) out;
	
	flat out int num;
	flat in int number[];
		
	void main(void)
	{
		num = number[0];
		// // // mat4 transform = uBboxData[2*num];
		mat4 transform = uBboxData[num];
		transform[0][3] = 0;
		transform[1][3] = 0;
		transform[2][3] = 0;
		transform[3][3] = 1;
		mat4 pvm = uProjectionMatrix * uViewMatrix * transform;
				
		vec4 pnt[8];
		pnt[0] = pvm * vec4( 0, 0, 0, 1 );
		pnt[1] = pvm * vec4( 1, 0, 0, 1 );
		pnt[2] = pvm * vec4( 1, 1, 0, 1 );
		pnt[3] = pvm * vec4( 0, 1, 0, 1 );		
		pnt[4] = pvm * vec4( 0, 0, 1, 1 );
		pnt[5] = pvm * vec4( 1, 0, 1, 1 );
		pnt[6] = pvm * vec4( 1, 1, 1, 1 );
		pnt[7] = pvm * vec4( 0, 1, 1, 1 );
		
		gl_Position = pnt[0]; EmitVertex();	gl_Position = pnt[1]; EmitVertex();	EndPrimitive();
		gl_Position = pnt[1]; EmitVertex();	gl_Position = pnt[2]; EmitVertex();	EndPrimitive();
		gl_Position = pnt[2]; EmitVertex();	gl_Position = pnt[3]; EmitVertex();	EndPrimitive();
		gl_Position = pnt[3]; EmitVertex();	gl_Position = pnt[0]; EmitVertex();	EndPrimitive();
		
		gl_Position = pnt[4]; EmitVertex();	gl_Position = pnt[5]; EmitVertex();	EndPrimitive();
		gl_Position = pnt[5]; EmitVertex();	gl_Position = pnt[6]; EmitVertex();	EndPrimitive();
		gl_Position = pnt[6]; EmitVertex();	gl_Position = pnt[7]; EmitVertex();	EndPrimitive();
		gl_Position = pnt[7]; EmitVertex();	gl_Position = pnt[4]; EmitVertex();	EndPrimitive();
		
		gl_Position = pnt[0]; EmitVertex();	gl_Position = pnt[4]; EmitVertex();	EndPrimitive();
		gl_Position = pnt[1]; EmitVertex();	gl_Position = pnt[5]; EmitVertex();	EndPrimitive();
		gl_Position = pnt[2]; EmitVertex();	gl_Position = pnt[6]; EmitVertex();	EndPrimitive();
		gl_Position = pnt[3]; EmitVertex();	gl_Position = pnt[7]; EmitVertex();	EndPrimitive();
	}
	
#endif	

#ifdef FRAGMENT_SHADER_WIRED
	
	flat in int num;
	in vec3 normal;
	
	out vec4 FragColor;
	
	void main(void)
	{		
		FragColor = vec4( uBboxData[num][0][3], uBboxData[num][1][3], uBboxData[num][2][3], uBboxData[num][3][3] );
		// mat4 colors = uBboxData[2*num+1];
		// // FragColor = vec4( colors[0][0], colors[1][0], colors[2][0], colors[3][0] );
		// FragColor = colors[0];
	}
	
#endif	